package com.pyq.agent2;

import java.io.File;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.CodeSource;

/**
 * @author pengYongQiang
 * @date 2021/2/5 10:08
 * <p>
 * 一：运行前代理
 * 1.定义一个premain方法，它将在main方法运行前执行
 * 2.编写MANIFEST.MF文件,maven项目用插件
 * 3.打Jar包
 * 4.在其他项目中添加启动参数 -javaagent:jar包路径
 *
 * 二：运行后代理
 * 1.定义一个agentmain方法
 * 2.编写MANIFEST.MF文件,maven项目用插件
 * 3.打Jar包
 * 4.写一个加载agent的程序，需要用到JAVA安装目录下的 jdk1.8.0_261\lib\tools.jar。
 *
 *
 *  1.主要API(java.lang.instrutment)
 *       1）ClassFileTransformer：定义了类加载前的预处理类，可以在这个类中对要加载的类的字节码做一些处理，譬如进行字节码增强
 *       2）Instrutmentation：增强器，由JVM在入口参数中传递给我们，提供了如下的功能
 *          addTransformer/ removeTransformer：注册/删除ClassFileTransformer
 *          retransformClasses：对于已经加载的类重新进行转换处理，即会触发重新加载类定义，需要注意的是，新加载的类不能修改旧有的类声明，譬如不能增加属性、不能修改方法声明
 *          redefineClasses：与如上类似，但不是重新进行转换处理，而是直接把处理结果(bytecode)直接给JVM
 *          getAllLoadedClasses：获得当前已经加载的Class，可配合retransformClasses使用
 *          getInitiatedClasses：获得由某个特定的ClassLoader加载的类定义
 *          getObjectSize：获得一个对象占用的空间，包括其引用的对象
 *          appendToBootstrapClassLoaderSearch/appendToSystemClassLoaderSearch：增加BootstrapClassLoader/SystemClassLoader的搜索路径
 *          isNativeMethodPrefixSupported/setNativeMethodPrefix：支持拦截Native Method
 */
public class Demo {


    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("premain，agentArgs：" + agentArgs);
    }

    //运行后代理
    public static void agentmain(String agentArgs, Instrumentation inst) {
        Class<?>[] allLoadedClasses = inst.getAllLoadedClasses();
        System.out.println("agentmain，agentArgs：" + agentArgs);
        System.out.println("加载类数量:" + allLoadedClasses.length);

        System.out.println("加载核心包12355");

        try {
            bind(inst, agentArgs);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public static void main(String[] args) {
        String s = "aaa,";
        System.out.println(s.substring(s.indexOf(",")+1));
    }
    private static void bind(Instrumentation inst, String agentArgs) throws Exception {
        System.out.println("=============================");
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();

        int i = agentArgs.indexOf(",");

        String path = agentArgs.substring(0, i);
        agentArgs = agentArgs.substring( i+1);

        String s = path + "core-1.0-SNAPSHOT.jar";
        s = s.replace("file:/", "");
        System.out.println(s);
        File file = new File(s);

        URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{file.toURI().toURL()});

        Class<?> aClass = urlClassLoader.loadClass("org.pyq.core.Main");
        Method method = aClass.getDeclaredMethod("getInstance", Instrumentation.class, String.class);

        try {
            Object invoke = method.invoke(null, inst, agentArgs);
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            e.printStackTrace();
        } finally {
            urlClassLoader.close();
        }
        System.out.println("加载完成");
    }

}
